﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="EntityPersitor.cs" company="Data Ductus Malmö">
//   (c) 2010 - 2012 Data Ductus Malmö AB
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace DataDuctus.Snmp.Persistor.Core.Persistor.Internal
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Net;

  using DataDuctus.Snmp.Persistor.Core.Attributes;
  using DataDuctus.Snmp.Persistor.Core.Extensions;
  using DataDuctus.Snmp.Persistor.Core.MetaData;

  using Lextm.SharpSnmpLib;
  using Lextm.SharpSnmpLib.Messaging;

  /// <summary>
  /// The entity persitor.
  /// </summary>
  internal static class EntityPersitor
  {
    #region Methods

    /// <summary>
    /// The save.
    /// </summary>
    /// <param name="classMeta">
    /// The class meta.
    /// </param>
    /// <param name="connectionMeta">
    /// The connection meta.
    /// </param>
    /// <param name="objects">
    /// The objects.
    /// </param>
    /// <typeparam name="T">
    /// </typeparam>
    internal static void Save<T>(ClassMeta classMeta, ConnectionMeta connectionMeta, IEnumerable<T> objects)
    {
      foreach (T obj in objects)
      {
        Save(classMeta, connectionMeta, obj);
      }
    }

    /// <summary>
    /// The save.
    /// </summary>
    /// <param name="classMeta">
    /// The class meta.
    /// </param>
    /// <param name="connectionMeta">
    /// The connection meta.
    /// </param>
    /// <param name="obj">
    /// The obj.
    /// </param>
    /// <typeparam name="T">
    /// </typeparam>
    /// <exception cref="Exception">
    /// </exception>
    internal static void Save<T>(ClassMeta classMeta, ConnectionMeta connectionMeta, T obj)
    {
      IEnumerable<PropertyMeta> properties = from property in classMeta.Properties
                                             where
                                               property.Access == PropertyAccess.ReadWrite
                                               || property.Access == PropertyAccess.WriteOnly
                                             select property;

      List<Variable> setList = (from property in properties
                                select
                                  new Variable(
                                  IndexCreator.CreateIndex(classMeta, property, obj), CreateData(property, obj))).ToList
        ();

      var request = new SetRequestMessage(
        Messenger.NextRequestId, connectionMeta.Version, new OctetString(connectionMeta.SecurityString), setList);

      var target = new IPEndPoint(connectionMeta.Host.ToIpAddress(), connectionMeta.Port);
      ISnmpMessage response = request.GetResponse(connectionMeta.Timeout, target);

      if (response.Scope.Pdu.ErrorStatus.ToInt32() != 0)
      {
        // != ErrorCode.NoError
        throw new Exception("Error while setting");
      }
    }

    /// <summary>
    /// The create data.
    /// </summary>
    /// <param name="property">
    /// The property.
    /// </param>
    /// <param name="instance">
    /// The instance.
    /// </param>
    /// <returns>
    /// The Lextm.SharpSnmpLib.ISnmpData.
    /// </returns>
    private static ISnmpData CreateData(PropertyMeta property, object instance)
    {
      return DataConverter.ConvertToSnmpType(property, property.Property.GetValue(instance, null));
    }

    #endregion
  }
}